package org.ehe.erp.service.stock.imp;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehe.common.core.exception.ServiceException;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.erp.domain.stock.ErpStock;
import org.ehe.erp.domain.stock.bo.ErpStockBo;
import org.ehe.erp.domain.stock.vo.ErpStockVo;
import org.ehe.erp.mapper.stock.ErpStockMapper;
import org.ehe.erp.service.stock.IErpStockService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author :zhangnn
 * @className :ErpStockServiceImpl
 * @description: TODO
 * @date 2025-08-28 17:07:12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ErpStockServiceImpl extends ServiceImpl<ErpStockMapper, ErpStock> implements IErpStockService {

    private final ErpStockMapper baseMapper;

    @Override
    public ErpStockVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public List<ErpStockVo> queryList(ErpStockBo bo) {
        LambdaQueryWrapper<ErpStock> lqw = buildQueryWrapper(bo);
        return baseMapper.selectStockList(lqw);
    }

    @Override
    public TableDataInfo<ErpStockVo> queryPageList(ErpStockBo bo, PageQuery page) {
        LambdaQueryWrapper<ErpStock> lqw = buildQueryWrapper(bo);
        IPage<ErpStockVo> erpStockVoIPage = this.baseMapper.selectVoPage(page.build(), lqw);
        return TableDataInfo.build(erpStockVoIPage);
    }

    private LambdaQueryWrapper<ErpStock> buildQueryWrapper(ErpStockBo bo) {
        LambdaQueryWrapper<ErpStock> lqw = new LambdaQueryWrapper<>();
        lqw.eq(bo.getProductId() != null, ErpStock::getProductId, bo.getProductId());
        lqw.eq(bo.getWarehouseId() != null, ErpStock::getWarehouseId, bo.getWarehouseId());
        lqw.ge(bo.getMinCount() != null, ErpStock::getCount, bo.getMinCount());
        lqw.le(bo.getMaxCount() != null, ErpStock::getCount, bo.getMaxCount());
        lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), ErpStock::getTenantId, bo.getTenantId());
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(ErpStockBo bo) {
        ErpStock add = BeanUtil.toBean(bo, ErpStock.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(ErpStockBo bo) {
        ErpStock update = BeanUtil.toBean(bo, ErpStock.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ErpStock entity) {
        // 校验产品和仓库组合是否已存在
        if (entity.getProductId() != null && entity.getWarehouseId() != null) {
            ErpStock existStock = baseMapper.selectByProductAndWarehouse(entity.getProductId(), entity.getWarehouseId());
            if (existStock != null && !existStock.getId().equals(entity.getId())) {
                throw new ServiceException("该产品在该仓库的库存记录已存在");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 可以在这里添加删除前的业务校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public ErpStockVo queryByProductAndWarehouse(Long productId, Long warehouseId) {
        ErpStock stock = baseMapper.selectByProductAndWarehouse(productId, warehouseId);
        return stock != null ? MapstructUtils.convert(stock, ErpStockVo.class) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStock(Long productId, Long warehouseId, BigDecimal quantity, String operation) {
        ErpStock stock = baseMapper.selectByProductAndWarehouse(productId, warehouseId);
        if (stock == null) {
            throw new ServiceException("库存记录不存在");
        }

        BigDecimal newCount;
        switch (operation.toUpperCase()) {
            case "IN": // 入库
                newCount = stock.getCount().add(quantity);
                break;
            case "OUT": // 出库
                newCount = stock.getCount().subtract(quantity);
                if (newCount.compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException("库存不足，无法出库");
                }
                break;
            case "SET": // 直接设置
                newCount = quantity;
                break;
            default:
                throw new ServiceException("不支持的操作类型：" + operation);
        }

        stock.setCount(newCount);
        return baseMapper.updateById(stock) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdateStock(List<ErpStockBo> stockList) {
        for (ErpStockBo bo : stockList) {
            updateByBo(bo);
        }
        return true;
    }

    @Override
    public List<ErpStockVo> queryLowStockProducts(BigDecimal threshold) {
        return baseMapper.selectLowStockProducts(threshold);
    }

    @Override
    public List<ErpStockVo> queryStockGroupByWarehouse() {
        return baseMapper.selectStockGroupByWarehouse(null);
    }

    @Override
    public Boolean isUniqueProductWarehouse(ErpStockBo bo) {
        ErpStock stock = baseMapper.selectByProductAndWarehouse(bo.getProductId(), bo.getWarehouseId());
        return stock == null || stock.getId().equals(bo.getId());
    }
}
